/**
 * 
 */
package org.istt.web;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.servlet.ServletContext;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.istt.domain.BaseObject;
import org.istt.domain.User;
import org.istt.service.Manager;
import org.istt.web.helper.ExtendedPaginatedList;
import org.istt.web.helper.PaginateListFactory;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

/**
 * @author Huy
 *
 */
public abstract class BaseAction<M extends Manager<T, ID>, T extends BaseObject<ID>, ID extends Serializable> extends ActionSupport {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -7662559080280452375L;
	protected final Log log = LogFactory.getLog(getClass());
	protected final String selDefKey = getText("select.default.key");
	protected Manager<T, ID> mgr;
	protected List<T> entities;
	protected ExtendedPaginatedList paginatedList;
    protected T entity;
    protected ID id;
    private String cancel;
    private String delete;
    private String search;
    protected PaginateListFactory paginateListFactory;
    private String savedMessage;
    private String deletedMessage;
    protected String username;
    protected User loggedUser;
    
    public BaseAction() {
    	username = SecurityContextHolder.getContext().getAuthentication().getName();
    	loggedUser = (User)ActionContext.getContext().getSession().get(WebConstants.USER_INFO);
    }
    
    public String getDocumentLocation(){
    	ServletContext servletContext = ServletActionContext.getServletContext();
    	String dirPaths = servletContext.getRealPath("");
    	return dirPaths.substring(0, dirPaths.lastIndexOf("\\"))+"\\template\\";
    }
    
    public String getSavedMessage() {
		return savedMessage;
	}

	public void setSavedMessage(String savedMessage) {
		this.savedMessage = savedMessage;
	}

	public String getDeletedMessage() {
		return deletedMessage;
	}

	public void setDeletedMessage(String deletedMessage) {
		this.deletedMessage = deletedMessage;
	}

	/**
	 * @return the now
	 */
	public DateTime getNow() {
		return DateTime.now();
	}

	/**
	 * @return the search
	 */
	public String getSearch() {
		return search;
	}

	/**
	 * @param search the search to set
	 */
	public void setSearch(String search) {
		this.search = search;
	}

	/**
	 * @param mgr the mgr to set
	 */
	public void setManager(Manager<T, ID> mgr) {
		this.mgr = mgr;
	}

	public void setCancel(String cancel) {
        this.cancel = cancel;
    }

    public void setDelete(String delete) {
        this.delete = delete;
    }
    
    public String getDelete() {
		return delete;
	}

	public List<T> getList() { 
        return entities; 
    }
    
    /**
	 * @return the entity
	 */
	public T getEntity() {
		return entity;
	}
	
	public abstract ID getId();

	public void setId(ID id) {
		this.id = id;
	}

	/**
	 * @param entity the entity to set
	 */
	public void setEntity(T entity) {
		this.entity = entity;
	}

	public String delete() {
		if (log.isDebugEnabled()) {
            log.debug("entering 'delete' method");
        }
		
        mgr.remove(getId());
        
        setDeleteMessage();
        if (!StringUtils.isEmpty(deletedMessage)) {
        	ActionContext.getContext().getSession()
						.put("message", getText(getDeletedMessage()));
        }
                
        return "delete";
    }
    
    @SuppressWarnings("unchecked")
	public String edit() throws Exception{
    	if (log.isDebugEnabled()) {
            log.debug("entering 'edit' method");
        }
        // check for an add
        if (getId() != null) {
        	if (log.isDebugEnabled()) {
                log.debug("id is not equal to null do editing entity");
            }
            entity = mgr.get(getId());
        } else {
        	if (log.isDebugEnabled()) {
                log.debug("id is equal to " + getId() +  " do creating entity");
            }
            entity = ((Class<T>) ((ParameterizedType) getClass()
    				.getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();
        }        
        return SUCCESS;
    }
    
    public String execute() {
    	if (log.isDebugEnabled()) {
            log.debug("entering 'execute' method");
        }
    	
        if (cancel != null) {
        	if (log.isDebugEnabled()) {
                log.debug("return 'cancel' result");
            }
            return "cancel";
        }
        
        if (delete != null) {
            return delete();
        }
        
        if (search != null) {
        	if (log.isDebugEnabled()) {
                log.debug("return 'search' result");
            }
            return "search";
        }
        
        return SUCCESS;
    }
    
    public String save() {
        if (log.isDebugEnabled()) {
            log.debug("entering 'save' method");
        }
        
        entity = getEntity();
        
    	mgr.save(entity);
    	setSaveMessage();// addition or edit message ??
        if (!StringUtils.isEmpty(savedMessage)) {
        	
        	
        	ActionContext.getContext().getSession()
						.put("message", getText(getSavedMessage()));
        	log.debug("Saved message is stored in session");
        } else {
        	log.debug("Saved message is empty");
        }
        
        return SUCCESS;
    }
    
    public String search() throws Exception {
    	if (log.isDebugEnabled()) {
            log.debug("entering 'search' method");
        }
    	entities = mgr.search(getEntity());
		return SUCCESS;
	}
    
    @Deprecated
    protected void setSaveMessage(){};
    
    @Deprecated
    protected void setDeleteMessage(){};
    
    /**
     * This is a deprecated method, use paginatedList instead 
     * @return 'success' forward 
     */
    @Deprecated
    public String list() {
    	if (log.isDebugEnabled()) {
            log.debug("entering 'list' method");
        }
        entities = mgr.getList();
        return SUCCESS; 
    }
    
    /**
     * Get paginated entities of a table
     * @return the list of entities
     */
    public String paginatedList() {
    	if (log.isDebugEnabled()) {
    		log.debug("entering 'paginatedList' method");
    	}
    	
    	ExtendedPaginatedList param = paginateListFactory.getPaginatedListFromRequest(ServletActionContext.getRequest());
    	paginatedList = mgr.getList(param);
    	return SUCCESS; 
    }
    
    public ExtendedPaginatedList getPaginatedList() {
		return paginatedList;
	}

	@Autowired
    public void setPaginateListFactory(PaginateListFactory paginateListFactory) {
        this.paginateListFactory = paginateListFactory;
    }
}
